package com.graphhopper.matching;

import com.google.common.collect.Maps;
import com.google.common.geometry.*;
import com.graphhopper.GraphHopper;
import com.graphhopper.util.shapes.GHPoint;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


public class TrajPoint {
    private String userId;
    private String lacId;
    private String cellId;
    private Double lon;
    private Double lat;
    private String timeId;
    private String btsType;

    public TrajPoint(String userId, String lacId, String cellId, Double lon, Double lat, String timeId, String btsType) {
        this.userId = userId;
        this.lacId = lacId;
        this.cellId = cellId;
        this.lon = lon;
        this.lat = lat;
        this.timeId = timeId;
        this.btsType = btsType;
    }
    public static void main(String[] args) {
        String relDir = args.length == 1 ? args[0] : "";
        String strosm = "./sichuan.osm.pbf";
        String hdfsosm = "hdfs://127.0.0.1:9000/target/sichuan.osm.pbf";

        ArrayList<String> origList = Trajmatch.InputFormatMy.formattxtFile("D:\\input\\ods\\ban-ttt.txt");

        ArrayList <TrajPoint> origTrajList = new ArrayList<>();
        for (String tmp : origList) {
            TrajPoint tmpTraj = new TrajPoint(
                    tmp.split(",")[0],
                    tmp.split(",")[1],
                    tmp.split(",")[2],
                    Double.parseDouble(tmp.split(",")[3]),
                    Double.parseDouble(tmp.split(",")[4]),
                    tmp.split(",")[5],
                    tmp.split(",")[6]
            );
                    origTrajList.add(tmpTraj);
        }

        generateTrajData(origTrajList);
    }

    //Clean duplicated in short time
    public static ArrayList<TrajPoint> trajClean(ArrayList arrayList) {
        if (null == arrayList) {
            return null;
        }

        ArrayList<TrajPoint> clean = new ArrayList<>();

        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");

        HashSet<String> distinct = new HashSet<>();

        try {
            for (int i = 0; i < arrayList.size(); i++) {

                TrajPoint tmpPoint = (TrajPoint)arrayList.get(i);

                long round_interval = df.parse(tmpPoint.getTimeId()).getTime() / 1000 / utils.Interval_Seconds ;

                String str_key = tmpPoint.getLon().toString() + "," + tmpPoint.getLat().toString() + "," + round_interval;

                if (!distinct.contains(str_key)) {
                    distinct.add(str_key);
                    clean.add((TrajPoint)arrayList.get(i));
                }
                else {
                    ;//System.out.println("clean " + arrayList.get(i).toString());
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return clean;
    }

    public static ArrayList<TrajPoint> trajDenoise(ArrayList arrayList) {
        ArrayList<TrajPoint> denoise = new ArrayList<>();
        denoise = (ArrayList<TrajPoint>) arrayList.clone();

        TrajPoint prev = null;
        TrajPoint curr = null;
        TrajPoint next = null;
        double dis = 0;
        double degree = 0;
        int pointNum = arrayList.size();
        int left = 0;
        int right = 0;

        while (left < pointNum - 2) {
            right = left + 1;
            try {
                prev = (TrajPoint) arrayList.get(left);

                while (right < pointNum - 1) {
                    curr = (TrajPoint) arrayList.get(right);
                    next = (TrajPoint) arrayList.get(right + 1);

                    //curr = prev , move the left window one step
                    if (curr.getLon().equals(prev.getLon()) && curr.getLat().equals(prev.getLat())) {
                        break;
                    }

                    //curr = next
                    if (curr.getLon().equals(next.getLon()) && curr.getLat().equals(next.getLat())) {
                        dis = utils.getDistance(curr.getLon(), curr.getLat(), prev.getLon(), prev.getLat());
                        if (dis > utils.Max_Distance) {
                            //remove next two, move right window, left window not change
                            //System.out.println("dis = " + dis + " denoise " + arrayList.get(right).toString());
                            denoise.remove(arrayList.get(right));
                            denoise.remove(arrayList.get(right+1));
                            right += 2;
                            continue;
                        }
                        else {
                            right += 1;
                            break;
                        }
                    }

                    //prev = next
                    if (prev.getLon().equals(next.getLon()) && prev.getLat().equals(next.getLat())) {
                        dis = utils.getDistance(curr.getLon(), curr.getLat(), prev.getLon(), prev.getLat());
                        if (dis > utils.Max_Distance) {
                            //remove next two, move right window, left window not change
                            //System.out.println("dis = " + dis + " denoise " + arrayList.get(right).toString());
                            denoise.remove(arrayList.get(right));
                            right += 1;
                            continue;
                        }
                        //valid point, move the slide window
                        break;
                    }

                    degree = utils.getDegree(curr.getLon(), curr.getLat(),
                            prev.getLon(), prev.getLat(),
                            next.getLon(), next.getLat());

                    if (degree < utils.Degree_Threshold) {
                        //System.out.println("degree = " + degree + " denoise " + arrayList.get(right).toString());
                        denoise.remove(arrayList.get(right));
                        right += 1;
                        continue;
                    }
                    //valid point, move the slide window
                    break;
                }
                //move window
                left = right;
            }

            catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        try {
            prev = (TrajPoint) denoise.get(denoise.size() - 1);
            curr = (TrajPoint) denoise.get(denoise.size() - 2);
            dis = utils.getDistance(curr.getLon(), curr.getLat(), prev.getLon(), prev.getLat());

            if (dis > utils.Max_Distance) {
                //remove the last dispersed point
                //System.out.println("dis = " + dis + " denoise " + denoise.get(denoise.size() - 1).toString());
                denoise.remove(denoise.size() - 1);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return denoise;
    }

    public static HashMap<Integer, ArrayList<TrajPoint>> trajAnalysis(ArrayList arrayList) {
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");

        int i = 0;
        int j = 0;
        int stayIndex = 1;
        int routeIndex = -1;
        TrajPoint left = null;
        TrajPoint right = null;
        TrajPoint prev_right = null;
        int diff = 0;
        double dis;
        boolean token = false;

        ArrayList<TrajPoint> stayPoint = null;
        ArrayList<TrajPoint> routePoint = null;
        HashMap<Integer, ArrayList<TrajPoint>> stayroutePointMap = new HashMap<>();

        int pointNum = arrayList.size();

        while (i < pointNum) {
            j = i + 1;
            token = false;
            try {
                left = (TrajPoint) arrayList.get(i);
                while (j < pointNum) {
                    right = (TrajPoint) arrayList.get(j);
                    prev_right = (TrajPoint) arrayList.get(j - 1);

                    // deal the last point
                    dis = utils.getDistance(left.getLon(), left.getLat(), right.getLon(), right.getLat());

                    if (j == pointNum - 1 && dis <= utils.Distance_Threshold) {//最后两个点的距离小于距离阈值
                        diff = (int) (
                                (
                                        df.parse(right.getTimeId()).getTime() - df.parse(left.getTimeId()).getTime()
                                ) / 1000
                        );

                        if (diff >= utils.Time_Threshold) {//最后两个点的停留时间大于时间阈值15分钟
                            if (stayPoint == null) {
                                stayPoint = new ArrayList<>();
                            }
                            for (int t = i; t < j + 1; t++) {
                                stayPoint.add((TrajPoint) arrayList.get(t));
                            }
                            stayroutePointMap.put(stayIndex, stayPoint);
                            stayPoint = null;
                            token = true;
                        }
                        i = j;
                        break;//将最后两个点放到stayPoint集合中
                    }

                    if (dis > utils.Distance_Threshold) {
                        diff = (int) (
                                (
                                        df.parse(prev_right.getTimeId()).getTime() - df.parse(left.getTimeId()).getTime()
                                ) / 1000
                        );
                        if (diff >= utils.Time_Threshold) {
                            if (stayPoint == null) {
                                stayPoint = new ArrayList<>();
                            }
                            for (int t = i; t < j; t++) {
                                stayPoint.add((TrajPoint) arrayList.get(t));
                            }
                            stayroutePointMap.put(stayIndex, stayPoint);
                            stayIndex ++;
                            stayPoint = null;
                            i = j - 1;
                            token = true;
                        }
                        break;
                    }
                    j += 1;
                }
                if (!token) {
                    if (routePoint == null) {
                        routePoint = new ArrayList<>();
                    }
                    routePoint.add((TrajPoint) arrayList.get(i));
                }
                else {
                    if (routePoint != null) {
                        stayroutePointMap.put(routeIndex, routePoint);
                        routePoint = null;
                        routeIndex--;
                    }
                }

                i += 1;
            }
            catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        if (routePoint != null) {
            stayroutePointMap.put(routeIndex, routePoint);
        }

        return stayroutePointMap;
    }

    public static HashMap<Integer, ArrayList<StayPoint>>trajSegment(HashMap<Integer, ArrayList<TrajPoint>> stayroutePointMapList) {
        HashMap<Integer, ArrayList<StayPoint>> stayroutePointMap = new HashMap<>();

        for (int key : stayroutePointMapList.keySet()) {
            if (key > 0) {
                ArrayList<StayPoint> stayPointList = new ArrayList<>();
                StayPoint sp = getWeightedLocation(stayroutePointMapList.get(key));
                stayPointList.add(sp);
                stayroutePointMap.put(key, stayPointList);
            }
        }

        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");

        for (int key : stayroutePointMapList.keySet()) {
            if (key < 0) {
                ArrayList<TrajPoint> obList = stayroutePointMapList.get(key);
                ArrayList<StayPoint> routePointList = new ArrayList<>();
                for (TrajPoint tmp : obList) {
                    double lng = tmp.getLon();
                    double lat = tmp.getLat();
                    long st;
                    try {
                        st = df.parse(tmp.getTimeId()).getTime();
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }

                    int radius;
                    if (tmp.getBtsType().equals("outdoor")) {
                        radius = utils.Outdoor_Radius;
                    }
                    else {
                        radius = utils.Indoor_Radius;
                    }

                    StayPoint sp = new StayPoint(new GHPoint(lat, lng), radius, st, 0);
                    routePointList.add(sp);
                }

                stayroutePointMap.put(key, routePointList);
            }
        }

        //System.out.println("traj segment size = " + stayroutePointMap.size());

        return stayroutePointMap;
    }

    public static ArrayList<Observation> trajReduce(ArrayList<StayPoint> arrayList) {
        int i = 0;
        int j = 0;
        StayPoint temp1 = null;
        StayPoint temp2 = null;
        int diff = 0;
        double lng,lat;
        long tm;

        ArrayList<Observation> samples = new ArrayList<>();
        ArrayList<Double> lngList = new ArrayList<>();
        ArrayList<Double> latList = new ArrayList<>();
        ArrayList<Long> tmList = new ArrayList<>();

        int pointNum = arrayList.size();

        while (i < pointNum) {
            j = i + 1;

            temp1 = arrayList.get(i);
            while (j < pointNum) {
                temp2 = arrayList.get(j);
                diff = (int) (temp2.getStarttime() - temp1.getStarttime()) / 1000;

                if (diff > utils.Reduce_Seconds) {
                    break;
                }

                lngList.add(temp2.getPoint().getLon());
                latList.add(temp2.getPoint().getLat());
                tmList.add(temp2.getStarttime());
                j += 1;
            }

            if (lngList.size() > 0) {
                lngList.add(temp1.getPoint().getLon());
                latList.add(temp1.getPoint().getLat());
                tmList.add(temp1.getStarttime());
                lng = lngList.stream().collect(Collectors.averagingDouble(x -> x));
                lat = latList.stream().collect(Collectors.averagingDouble(x -> x));
                tm = (tmList.stream().collect(Collectors.averagingLong(x -> x))).longValue();
                lng = new BigDecimal(lng).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();
                lat = new BigDecimal(lat).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();
                Observation sample = new Observation(new GHPoint(lat, lng), tm, utils.Outdoor_Radius);
                samples.add(sample);
                lngList.clear();
                latList.clear();
                tmList.clear();
            }
            else {
                lng = new BigDecimal(temp1.getPoint().getLon()).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();
                lat = new BigDecimal(temp1.getPoint().getLat()).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();
                tm = temp1.getStarttime();
                Observation sample = new Observation(new GHPoint(lat, lng), tm, utils.Outdoor_Radius);
                samples.add(sample);
            }
            i = j;
        }

        return samples;
    }

    public static StayPoint getWeightedLocation(ArrayList<TrajPoint> origList) {
        ArrayList<Observation> weightedList = new ArrayList<>();

        double lng, lat;
        double radius = 0;
        long st = 0;

        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        ArrayList<Observation> obList = new ArrayList<>();
        try {
            for (TrajPoint tmp : origList) {
                lng = tmp.getLon();
                lat = tmp.getLat();
                st = df.parse(tmp.getTimeId()).getTime();
                if (tmp.getBtsType().equals("outdoor")) {
                    radius = utils.Outdoor_Radius;
                }
                else {
                    radius = utils.Indoor_Radius;
                }
                obList.add(new Observation(new GHPoint(lat, lng), st, (int) radius));
            }
        }catch (Exception e) {
            e.printStackTrace();
        }

        int ct_indoor = 0;
        // outdoor: distinct ; indoor: not distinct
        for (Observation o : obList) {
            if (o.getRadius() == utils.Outdoor_Radius) {
                if (!weightedList.contains(o)) {
                    weightedList.add(o);
                }
            }
            else {
                weightedList.add(o);
                ct_indoor ++;
            }
        }

        boolean isconfidence = false;
        if (ct_indoor >= utils.Min_Indoor_Count) {
            //indoor centroid
            isconfidence = true;
        }

        int fix = 1000;
        double centroidX = 0, centroidY = 0, plusW = 0;

        for (Observation latLng : weightedList) {
            plusW += fix / latLng.getRadius();
        }

        for (Observation latLng: weightedList) {
            if (isconfidence) {
                if (latLng.getRadius() == utils.Indoor_Radius) {
                    centroidX += latLng.getPoint().getLon();
                    centroidY += latLng.getPoint().getLat();
                }
            }
            else {
                centroidX += latLng.getPoint().getLon() * ((fix / latLng.getRadius()) / plusW);
                centroidY += latLng.getPoint().getLat() * ((fix / latLng.getRadius()) / plusW);
            }
        }

        double dis = 0;

        for (Observation latLng : weightedList) {
            dis += utils.getDistance(latLng.getPoint().getLon(), latLng.getPoint().getLat(), centroidX, centroidY);
        }

        if (weightedList.size() == 1) {
            dis = weightedList.get(0).getRadius();
        }

        dis = dis / weightedList.size();

        if (isconfidence) {
            centroidX = centroidX / ct_indoor;
            centroidY = centroidY / ct_indoor;
            radius = utils.Indoor_Radius;
        }
        else {
            radius = dis / utils.Outdoor_Confidence;
        }

        centroidX = new BigDecimal(centroidX).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();
        centroidY = new BigDecimal(centroidY).setScale(utils.Double_Scale, BigDecimal.ROUND_HALF_UP).doubleValue();

        /*System.out.println("centroid coord = " + centroidX + "," + centroidY +
                "  and radius = " + (int)radius +
                "  and confidence = " + isconfidence);*/

        long s2cell = getStayCell(centroidY, centroidX, radius);
        System.out.println("s2cell = " + s2cell);

        int stayt = (int)(obList.get(obList.size() - 1).getTime() - obList.get(0).getTime()) / 1000 / 60;
        return new StayPoint(new GHPoint(centroidY, centroidX),
                (int)radius, obList.get(0).getTime(), stayt);
    }

    public static long getStayCell(double lat, double lng, double r) {
        int currentLevel = 16;

        S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);
        S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);
        System.out.println("Target cellId = " + cellId.id());

        S2LatLng s2out = new S2CellId(cellId.id()).toLatLng();
        double latout = s2out.latDegrees();
        double lngout = s2out.lngDegrees();
        System.out.println("lngout = " + lngout + " latout = " + latout);

        double capHeight = (2 * S2.M_PI) * (r / utils.kEarthCircumferenceMeters);
        S2LatLng s2LatLng1= S2LatLng.fromDegrees(lat, lng);
        S2Cap cap = S2Cap.fromAxisHeight(s2LatLng1.toPoint(),capHeight * capHeight / 2);
        System.out.println("radius = " + r + " area = " + cap.area() * utils.EARTH_RADIUS * utils.EARTH_RADIUS);
        S2LatLngRect s2bound = cap.getRectBound();

        ArrayList<S2Point>  vertices = new ArrayList<>();

        //按照逆时针顺序添加
        vertices.add(S2LatLng.fromDegrees(30.701368518399796,104.02627461190419).toPoint());
        vertices.add(S2LatLng.fromDegrees(30.699328729316257,104.02887101670349).toPoint());
        vertices.add(S2LatLng.fromDegrees(30.701492595650798,104.03252420632933).toPoint());
        vertices.add(S2LatLng.fromDegrees(30.70381116549,104.02985576959131).toPoint());
        vertices.add(S2LatLng.fromDegrees(30.701368518399796,104.02627461190419).toPoint());
        S2Loop s2Loop = new S2Loop(vertices);
        S2Polygon s2polygon = new S2Polygon(s2Loop);
        System.out.println("s2polygon area = " + s2polygon.getArea() * utils.EARTH_RADIUS * utils.EARTH_RADIUS);

        S2RegionCoverer coverer = S2RegionCoverer.builder().
                setLevelMod(1).
                setMaxLevel(14).
                setMinLevel(18).
                setMaxCells(100).
                build();

        ArrayList<S2CellId> arrcell = new ArrayList<>();
        //S2CellUnion covering = coverer.getCovering(s2polygon);
        S2CellUnion covering = coverer.getCovering(cap);

        boolean b = false;
        for (S2CellId s2CellId : covering.cellIds()) {
            b = cap.mayIntersect(new S2Cell(s2CellId));
            if (b) {
                System.out.println("Intersect cellid = " + s2CellId + " id = " + s2CellId.id());
                break;
            }
        }

        if (b)
            System.out.println("Intersect");
        else
            System.out.println("Not Intersect");


        Map<Integer,Integer> sizeCountMap= Maps.newHashMap();
        StringBuilder sb3 = new StringBuilder();
        S2Region s2Region = S2Util.getS2RegionByCircle(lat,lng, r);

        List<S2CellId> cellIdListByPolygon = S2Util.getCompactCellIdList(s2Region);
        cellIdListByPolygon.forEach(s2CellId -> {
            //System.out.println("Level:" + s2CellId.level() + ",ID:" + s2CellId.toToken() + ",Min:" + s2CellId.rangeMin().toToken() + ",Max:" + s2CellId.rangeMax().toToken());
            sb3.append(",").append(s2CellId.toToken());
            sizeCountMap.put(s2CellId.level(),sizeCountMap.getOrDefault(s2CellId.level(),0)+1);
        });
        System.out.println(sb3.substring(1));
        System.out.println("totalSize:"+cellIdListByPolygon.size());
        sizeCountMap.entrySet().forEach(integerIntegerEntry -> {
            ;//System.out.printf("level:%d,size:%d\n",integerIntegerEntry.getKey(),integerIntegerEntry.getValue());
        });

        return cellId.id();
    }

    public static void  generateTrajData(ArrayList<TrajPoint> origList) {
        String userId = origList.get(0).getUserId();
        //System.out.println("original size = " + origList.size());

        ArrayList<TrajPoint> cleanList = trajClean(origList);
        //System.out.println("clean size = " + cleanList.size());

        ArrayList<TrajPoint> denoiseList = trajDenoise(cleanList);
/*        System.out.println("denoise size = " + denoiseList.size());

        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\input\\single\\denoise.txt"))) {
            for (TrajPoint tmp : denoiseList) {
                bufferedWriter.write(tmp.toString());
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        HashMap<Integer, ArrayList<TrajPoint>> stayroutePointMapList = trajAnalysis(denoiseList);  //分段
        HashMap<Integer, ArrayList<StayPoint>> stayroutePointMap = trajSegment(stayroutePointMapList); //聚合

        List<List<Observation>> routePointList = new ArrayList<>();//移动点压缩集合
        List<StayPoint> stayPointList = new ArrayList<>();//停留点聚合集合
        for (Integer index : stayroutePointMap.keySet()) {
            if (index<0){
                routePointList.add(trajReduce(stayroutePointMap.get(index)));//压缩
            }else{
                stayPointList.addAll(stayroutePointMap.get(index));
            }
        }

        /**生成dwd_stay_day数据**/
        List<StayDayData> stayDayList = new ArrayList<>();
        for (int i = 0; i <stayPointList.size(); i++) {
            Integer stayId = i+1;
            StayPoint stayPoint = stayPointList.get(i);
            Double centroidLon = stayPoint.getPoint().getLon();
            Double centroidLat = stayPoint.getPoint().getLat();
            Integer radius = stayPoint.getRadius();
            Integer locType = radius==utils.Outdoor_Radius?1:0;
            String startTime = utils.milli2Date(stayPointList.get(i).getStarttime());
            Integer stayTime = stayPoint.getStaytime();
            StayDayData stayDayData = new StayDayData(userId, stayId, centroidLon, centroidLat, radius, locType, startTime, stayTime);
            stayDayList.add(stayDayData);
        }
        //System.out.println("生成dwd_stay_day数据");
        //System.out.println(stayDayList);
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\input\\data\\dwd_stay_day.txt",true))) {
            for (StayDayData data : stayDayList) {
                bufferedWriter.write(data.toString());
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        /**生成dwd_stay_detail_day数据**/
        List<StayDetailDayData> stayDetailDayDataList = new ArrayList<>();
        for (Integer index : stayroutePointMapList.keySet()) {
            if (index>0){
                List<TrajPoint> orgStayDatas = stayroutePointMapList.get(index);
                for (TrajPoint orgStayData:orgStayDatas) {
                    stayDetailDayDataList.add(new StayDetailDayData(userId,index,orgStayData.getLacId(),orgStayData.getCellId(),orgStayData.getTimeId()));
                }
            }
        }
        //System.out.println("生成dwd_stay_detail_day数据");
        //System.out.println(stayDetailDayDataList);
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\input\\data\\dwd_stay_detail_day.txt",true))) {
            for (StayDetailDayData data : stayDetailDayDataList) {
                bufferedWriter.write(data.toString());
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        /**生成dwd_route_detail_day数据**/
        List<RouteDetailDayData> routeDetailDayDataList = new ArrayList<>();
        List<List<RouteDetailDayData>> routeDetailDayDataLists = new ArrayList<>();
        int routeDetailIndex = 1;
        for (List<Observation> observations:routePointList){
            List<RouteDetailDayData> preRouteDetailDayDataList = new ArrayList<>();
            for (Observation observation:observations) {
                long routeTime = observation.getTime();
                String routeTimeStr = utils.milli2Date(routeTime);
                routeDetailDayDataList.add(new RouteDetailDayData(userId,routeDetailIndex,observation.getPoint().getLon(),observation.getPoint().getLat(),routeTimeStr));
                preRouteDetailDayDataList.add(new RouteDetailDayData(userId,routeDetailIndex,observation.getPoint().getLon(),observation.getPoint().getLat(),routeTimeStr));
            }
            routeDetailDayDataLists.add(preRouteDetailDayDataList);
            routeDetailIndex++;
        }

        //System.out.println("生成dwd_route_detail_day数据");
        //System.out.println(routeDetailDayDataList);
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\input\\data\\dwd_route_detail_day.txt",true))) {
            for (RouteDetailDayData data : routeDetailDayDataList) {
                bufferedWriter.write(data.toString());
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        /**生成dwd_route_day数据**/
        List<RouteDayData> routeDayDataList = new ArrayList<>();
        for (List<RouteDetailDayData> routeDetailDayDatas :routeDetailDayDataLists) {
            String startTime = routeDetailDayDatas.get(0).getTimeId();
            String endTime = routeDetailDayDatas.get(routeDetailDayDatas.size()-1).getTimeId();
            Integer startId = 0;
            Integer endId = 0;
            List<Integer> startStayIndexList = new ArrayList<>();
            List<Integer> endStayIndexList = new ArrayList<>();
            for (StayDayData stayDayData:stayDayList) {
                String stayStartTime = stayDayData.getStartTime();
                try {
                    String stayEndTime = utils.milli2Date(new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(stayStartTime).getTime() + 60*1000*stayDayData.getStayTime());
                    if (startTime.compareTo(stayEndTime)>0){
                        startId = stayDayData.getStayId();
                        startStayIndexList.add(startId);
                    }
                    if (endTime.compareTo(stayStartTime)<0){
                        endId = stayDayData.getStayId();
                        endStayIndexList.add(endId);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            double distance = 0D;
            if (!startStayIndexList.isEmpty()){
                startId = startStayIndexList.get(startStayIndexList.size()-1);
                distance += utils.getDistance(stayDayList.get(startStayIndexList.size()-1).getCentroidLon(),stayDayList.get(startStayIndexList.size()-1).getCentroidLat(),
                        routeDetailDayDatas.get(0).getLon(),routeDetailDayDatas.get(0).getLat());
                String startStayTime = stayDayList.get(startStayIndexList.size()-1).getStartTime();
                Integer stayStayTime = stayDayList.get(startStayIndexList.size()-1).getStayTime();

                try {
                    startTime = utils.milli2Date(new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(startStayTime).getTime() + 60*1000*stayStayTime);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }
            if (!endStayIndexList.isEmpty()){
                endId = endStayIndexList.get(0);
                distance += utils.getDistance(stayDayList.get(endStayIndexList.get(0)-1).getCentroidLon(),stayDayList.get(endStayIndexList.get(0)-1).getCentroidLat(),
                        routeDetailDayDatas.get(routeDetailDayDatas.size()-1).getLon(),routeDetailDayDatas.get(routeDetailDayDatas.size()-1).getLat());
                endTime = stayDayList.get(endStayIndexList.get(0)-1).getStartTime();
            }
            for (int i = 1; i < routeDetailDayDatas.size(); i++) {
                distance += utils.getDistance(routeDetailDayDatas.get(i-1).getLon(),routeDetailDayDatas.get(i-1).getLat(),
                        routeDetailDayDatas.get(i).getLon(),routeDetailDayDatas.get(i).getLat());
            }

            try {
                Double routeTime = (new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(endTime).getTime()-new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(startTime).getTime())/(60*1000.0);
                Double speed = 0D;
                if (Math.abs(routeTime) > 0.001) {
                    speed = distance / 1000 / (routeTime / 60);
                }
                routeDayDataList.add(new RouteDayData(userId,routeDetailDayDatas.get(0).getRouteId(),
                        startId,endId,(int)Math.round(distance),(int)Math.round(speed),0,startTime,(int)Math.round(routeTime)));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        //System.out.println("生成dwd_route_day数据");
        //System.out.println(routeDayDataList);
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\input\\data\\dwd_route_day.txt",true))) {
            for (RouteDayData data : routeDayDataList) {
                bufferedWriter.write(data.toString());
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getLacId() {
        return lacId;
    }

    public void setLacId(String lacId) {
        this.lacId = lacId;
    }

    public String getCellId() {
        return cellId;
    }

    public void setCellId(String cellId) {
        this.cellId = cellId;
    }

    public Double getLon() {
        return lon;
    }

    public void setLon(Double lon) {
        this.lon = lon;
    }

    public Double getLat() {
        return lat;
    }

    public void setLat(Double lat) {
        this.lat = lat;
    }

    public String getTimeId() {
        return timeId;
    }

    public void setTimeId(String timeId) {
        this.timeId = timeId;
    }

    public String getBtsType() {
        return btsType;
    }

    public void setBtsType(String btsType) {
        this.btsType = btsType;
    }

    @Override
    public String toString() {
        return userId + "," +
                lacId + "," +
                cellId + "," +
                lon + "," +
                lat + "," +
                timeId + "," +
                btsType ;
    }
}
